/*
 * @文件描述:此类用于解析socket字符串，并将指令封装成字符串发送
 * @版本:
 * @作者:周晨阳
 * @Date:2021-09-30 09:56:20
 外部通过请求command来发送数据，或者注册回调函数，来接收对方发送的数据
 */

using System;
using System.Collections;
using System.Collections.Generic;
using Motor_Control;
using System.Text;
using System.Threading;
using static Motor_Control.COM_CODE;

namespace Motor_Control
{
    /// <summary>
    /// 传输数据相关枚举
    /// </summary>
    public class COM_CODE
    {
        /// <summary>
        /// 请求类型
        /// </summary>
        public enum REQUEST_CODE
        {
            NONE,
            SEND,//主动方发送数据,通常用于长数据传输
            REQUEST_DATA,//主动方请求被动方发送数据给主动方,通常用于请求对方发送数据
            COMMAND,//主动发请求被动方执行指令,通常用于让对方执行指令,和SEND类似，相当于发送很少数据的send
        }
        /// <summary>
        /// 传输的数据类型
        /// </summary>
        public enum TYPE_CODE
        {
            NONE,
            MOTOR_POS,
            STOP_MOTOR,
            HAND_CONTROL,
            MOTOR_RAW_CONTROL,
            SENSOR_ANGLE
        }
    }

    /// <summary>
    /// 带一个参数的指令
    /// </summary>
    /// <typeparam name="T0"></typeparam>
    public class RequestCommand<T0>
    {

        public REQUEST_CODE r;
        public TYPE_CODE t;
        public T0 value0;
        public string callbackKey;
        /// <summary>
        /// 生成一个不用回调函数的RequestCommand
        /// </summary>
        /// <param name="r">REQUEST_CODE</param>
        /// <param name="t">TYPE_CODE</param>
        /// <param name="value0">需要传输的数据</param>
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            callbackKey = r.ToString() + t.ToString();


        }
        /// <summary>
        /// 生成一个需要回调函数的RequestCommand
        /// </summary>
        /// <param name="r">REQUEST_CODE</param>
        /// <param name="t">TYPE_CODE</param>
        /// <param name="value0">需要传输的数据</param>
        /// <param name="action">回调函数</param>
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, Action<object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);


        }
        /// <summary>
        /// 生成一个需要回调函数的RequestCommand
        /// </summary>
        /// <param name="r">REQUEST_CODE</param>
        /// <param name="t">TYPE_CODE</param>
        /// <param name="value0">需要传输的数据</param>
        /// <param name="action">回调函数</param>
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, Action<object, object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }
        /// <summary>
        /// 生成一个需要回调函数的RequestCommand
        /// </summary>
        /// <param name="r">REQUEST_CODE</param>
        /// <param name="t">TYPE_CODE</param>
        /// <param name="value0">需要传输的数据</param>
        /// <param name="action">回调函数</param>
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, Action<object, object, object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            callbackKey = r.ToString() + t.ToString();


            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);
        }
        /// <summary>
        /// 执行RequestCommand,该操作会发送指令给对方
        /// </summary>
        public void execute()
        {
            StringBuilder str = Analysis.formatString(r, t, 1);
            str.Append("Value[0]=" + value0.ToString() + ";");
            MySocket.Send(MySocket.getWorkingSocket(), str.ToString());

        }
        /// <summary>
        /// 设置回调函数
        /// </summary>
        /// <param name="action"></param>
        public void setCallback(Action<object> action)
        {
            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);

        }
        /// <summary>
        /// 设置回调函数
        /// </summary>
        /// <param name="action"></param>
        public void setCallback(Action<object, object> action)
        {
            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }
        /// <summary>
        /// 设置回调函数
        /// </summary>
        /// <param name="action"></param>
        public void setCallback(Action<object, object, object> action)
        {
            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);

        }

    }

    /// <summary>
    /// 带两个参数的指令
    /// </summary>
    /// <typeparam name="T0"></typeparam>
    /// <typeparam name="T1"></typeparam>
    public class RequestCommand<T0, T1>
    {

        public REQUEST_CODE r;
        public TYPE_CODE t;
        public T0 value0;
        public T1 value1;
        public string callbackKey;
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            callbackKey = r.ToString() + t.ToString();


        }
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, Action<object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);


        }
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, Action<object, object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, Action<object, object, object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            callbackKey = r.ToString() + t.ToString();


            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);
        }

        public void execute()
        {
            StringBuilder str = Analysis.formatString(r, t, 2);
            str.Append("Value[0]=" + value0.ToString() + ";");
            str.Append("Value[1]=" + value1.ToString() + ";");
            MySocket.Send(MySocket.getWorkingSocket(), str.ToString());

        }
        /// <summary>
        /// 设置回调函数
        /// </summary>
        /// <param name="action"></param>
        public void setCallback(Action<object> action)
        {
            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);

        }
        public void setCallback(Action<object, object> action)
        {
            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }

        public void setCallback(Action<object, object, object> action)
        {
            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);

        }

    }

    /// <summary>
    /// 带三个参数的指令
    /// </summary>
    /// <typeparam name="T0"></typeparam>
    /// <typeparam name="T1"></typeparam>
    /// <typeparam name="T2"></typeparam>
    public class RequestCommand<T0, T1, T2>
    {

        public REQUEST_CODE r;
        public TYPE_CODE t;
        public T0 value0;
        public T1 value1;
        public T2 value2;
        public string callbackKey;
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, T2 value2)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            this.value2 = value2;
            callbackKey = r.ToString() + t.ToString();


        }
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, T2 value2, Action<object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            this.value2 = value2;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);


        }
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, T2 value2, Action<object, object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            this.value2 = value2;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }
        public RequestCommand(REQUEST_CODE r, TYPE_CODE t, T0 value0, T1 value1, T2 value2, Action<object, object, object> action)
        {
            this.r = r;
            this.t = t;
            this.value0 = value0;
            this.value1 = value1;
            this.value2 = value2;
            callbackKey = r.ToString() + t.ToString();


            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);
        }

        /// <summary>
        /// 执行命令,相当于用socket发送对应的字符串
        /// </summary>
        public void execute()
        {
            StringBuilder str = Analysis.formatString(r, t, 3);
            str.Append("Value[0]=" + value0.ToString() + ";");
            str.Append("Value[1]=" + value1.ToString() + ";");
            str.Append("Value[2]=" + value2.ToString() + ";");
            MySocket.Send(MySocket.getWorkingSocket(), str.ToString());

        }
        /// <summary>
        /// 设置回调函数
        /// </summary>
        /// <param name="action"></param>
        public void setCallback(Action<object> action)
        {
            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);

        }
        public void setCallback(Action<object, object> action)
        {
            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }

        public void setCallback(Action<object, object, object> action)
        {
            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);

        }

    }
    /// <summary>
    /// 处理接收请求
    /// </summary>
    public class InvokeCommand
    {
        public REQUEST_CODE r;
        public TYPE_CODE t;
        public string callbackKey;
        public InvokeCommand(REQUEST_CODE r, TYPE_CODE t, Action<object> action)
        {
            this.r = r;
            this.t = t;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithOneArg.ContainsKey(callbackKey))
                Analysis.CallbackWithOneArg.Add(callbackKey, action);


        }
        public InvokeCommand(REQUEST_CODE r, TYPE_CODE t, Action<object, object> action)
        {
            this.r = r;
            this.t = t;
            callbackKey = r.ToString() + t.ToString();

            if (!Analysis.CallbackWithTwoArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithTwoArgs.Add(callbackKey, action);

        }
        public InvokeCommand(REQUEST_CODE r, TYPE_CODE t, Action<object, object, object> action)
        {
            this.r = r;
            this.t = t;
            callbackKey = r.ToString() + t.ToString();


            if (!Analysis.CallbackWithThreeArgs.ContainsKey(callbackKey))
                Analysis.CallbackWithThreeArgs.Add(callbackKey, action);
        }

    }
    /// <summary>
    /// 字符串解析类
    /// </summary>
    public static class Analysis
    {
        //创建3个字典，用于保存不同参数个数的action
        public static Dictionary<string, Action<object>> CallbackWithOneArg = new Dictionary<string, Action<object>>();
        public static Dictionary<string, Action<object, object>> CallbackWithTwoArgs = new Dictionary<string, Action<object, object>>();
        public static Dictionary<string, Action<object, object, object>> CallbackWithThreeArgs = new Dictionary<string, Action<object, object, object>>();

        /// <summary>
        /// 生成规定格式的字符串,遵循Request=1;Type=1;Conut=1;Value[0]=100;这种格式
        /// </summary>
        /// <param name="r">REQUEST_CODE</param>
        /// <param name="t">TYPE_CODE</param>
        /// <param name="count">value的数量</param>
        /// <returns></returns>
        public static StringBuilder formatString(REQUEST_CODE r, TYPE_CODE t, int count)
        {
            StringBuilder str = new StringBuilder();
            str.Append("Request=");
            str.Append((int)r);
            str.Append(";");

            str.Append("Type=");
            str.Append((int)t);
            str.Append(";");

            str.Append("Count=");
            str.Append(count.ToString());
            str.Append(";");
            return str;

        }

        /// <summary>
        /// 解析字符串并自动调用相应的回调函数或者调用本地函数
        /// </summary>
        /// <param name="s"></param>
        public static void analysisString(string s)
        {
            //Console.WriteLine("content" + s);
            //检查是否为规定格式的指令,若不是就直接退出
            if (s.IndexOf("Request=") <= -1 && s.IndexOf("Type=") <= -1 && s.IndexOf("Count=") <= -1)
            {
                return;
            }
            try
            {
                REQUEST_CODE r = REQUEST_CODE.NONE;
                TYPE_CODE typeCode = TYPE_CODE.NONE;
                int Count = 0;
                Action<object> callback1 = null;
                Action<object, object> callback2 = null;
                Action<object, object, object> callback3 = null;
                object value0, value1, value2;
                string[] args = s.Split(new char[2] { '=', ';' });
                r = (REQUEST_CODE)int.Parse(args[1]);
                typeCode = (TYPE_CODE)int.Parse(args[3]);
                string callbackKey = null;

                //根据REQUEST_CODE和TYPE_CODE创建key来寻找对应的action
                if (r == REQUEST_CODE.REQUEST_DATA)
                {
                    callbackKey = REQUEST_CODE.SEND.ToString() + typeCode.ToString(); ;

                }
                else if (r == REQUEST_CODE.SEND)
                {
                    callbackKey = REQUEST_CODE.REQUEST_DATA.ToString() + typeCode.ToString(); ;

                }
                else if (r == REQUEST_CODE.COMMAND)
                {
                    callbackKey = REQUEST_CODE.COMMAND.ToString() + typeCode.ToString(); ;

                }
                Count = int.Parse(args[5]);

                if (CallbackWithOneArg.ContainsKey(callbackKey))
                {
                    callback1 = CallbackWithOneArg[callbackKey];

                }
                if (CallbackWithTwoArgs.ContainsKey(callbackKey))
                {
                    callback2 = CallbackWithTwoArgs[callbackKey];

                }
                if (CallbackWithThreeArgs.ContainsKey(callbackKey))
                {
                    callback3 = CallbackWithThreeArgs[callbackKey];

                }

                if (callback1 != null)
                {
                    value0 = (args[7]);
                    callback1(value0);
                }
                if (callback2 != null)
                {
                    value0 = (args[7]);
                    value1 = (args[9]);

                    callback2(value0, value1);
                }

                if (callback3 != null)
                {
                    value0 = (args[7]);
                    value1 = (args[9]);
                    value2 = (args[11]);

                    callback3(value0, value1, value2);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

    }
}
